package org.videopractice.common;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
/**
 * 类辅助工具：提供APP内包扫描、Class反射赋值\构建、等功能
 */
public class ClassUtils {

    /**
     * 构造一个指定类型实例
     * @param dstClass 指定的类型
     * @param initArgs 构造参数表
     * @param <T> 返回的实体类型
     * @return 返回一个实体，如果构造发生意外，返回的可能为null。
     */
    public static <T> T newInstance(Class<T> dstClass, Object... initArgs) {
        try {
            if(initArgs == null || initArgs.length <= 0) {
                return dstClass.getDeclaredConstructor().newInstance();
            } else {
                Class<?>[] parameterTypes = new Class[initArgs.length];
                for (int index = 0; index < parameterTypes.length; index++) {
                    parameterTypes[index] = initArgs[index].getClass();
                }
                Constructor<T> constructor = dstClass.getDeclaredConstructor(parameterTypes);
                return constructor.newInstance(initArgs);
            }
        } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 反射获取 {@code object} 中的 {@code field} 的值
     * @param field 字段
     * @param object 目标对象
     * @param <T> 字段值类型
     * @return 字段值
     */
    public static <T> T getFieldValue(Field field, Object object) {
        T fieldValue = null;
        try {
            boolean oldAccessible = field.isAccessible();
            if(!oldAccessible) field.setAccessible(true);

            fieldValue = (T) field.get(object);

            if(!oldAccessible) field.setAccessible(false);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return fieldValue;
    }

    /**
     * 反射赋值设置 {@code object} 中的 {@code field} 的值为 {@code fieldValue}
     * @param field 字段
     * @param object 目标对象
     * @param fieldValue 字段值
     * @return 是否设置成功， true 为赋值设置成功， false 为赋值设置失败，可能由于字段无法访问或类型无法转换引起
     */
    public static boolean setFieldValue(Field field, Object object, Object fieldValue) {
        try {
            boolean oldAccessible = field.isAccessible();
            if(!oldAccessible) field.setAccessible(true);

            field.set(object, fieldValue);

            if(!oldAccessible) field.setAccessible(false);

            return true;
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return false;
    }

}
